package com.sh.data.engine.domain.dataasset.service.impl;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.parser.SQLParserUtils;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import com.alibaba.druid.sql.visitor.SchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.util.JdbcConstants;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sh.data.engine.common.enumDefinition.DSType;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.ServletUtils;
import com.sh.data.engine.domain.base.model.enums.Database;
import com.sh.data.engine.domain.common.model.domain.DataFlow;
import com.sh.data.engine.domain.common.model.domain.LogRecord;
import com.sh.data.engine.domain.common.service.SqlflowService;
import com.sh.data.engine.domain.dataasset.model.domain.LineageDomain;
import com.sh.data.engine.domain.dataasset.model.domain.LineageMapDomain;
import com.sh.data.engine.domain.dataasset.model.domain.TableInfoBizDomain;
import com.sh.data.engine.domain.dataasset.model.domain.TableLineageDomain;
import com.sh.data.engine.domain.dataasset.model.domain.TableLineageDomain.Relation;
import com.sh.data.engine.domain.dataasset.model.domain.TableLineageDomain.TableNode;
import com.sh.data.engine.domain.dataasset.model.param.QueryTableParam;
import com.sh.data.engine.domain.dataasset.service.LineageService;
import com.sh.data.engine.domain.dataasset.service.TableProductService;
import com.sh.data.engine.domain.dataasset.service.TableService;
import com.sh.data.engine.domain.dataasset.service.TblPropService;
import com.sh.data.engine.domain.datadev.offline.service.DatadevJobService;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceDetailDomain;
import com.sh.data.engine.domain.integration.datasource.model.domain.DataSourceDomain;
import com.sh.data.engine.domain.integration.datasource.service.DataSourceService;
import com.sh.data.engine.domain.integration.offline.model.domain.FieldInfo;
import com.sh.data.engine.domain.util.ConvertUtil;
import com.sh.data.engine.domain.util.SQLUtil;
import com.sh.data.engine.domain.util.SqlParserUtil;
import com.sh.data.engine.repository.dao.dataasset.LineageMapper;
import com.sh.data.engine.repository.dao.dataasset.entity.LineageEntity;
import com.sh.data.engine.repository.dao.dataasset.entity.TableProductEntity;
import com.sh.data.engine.repository.dao.dataasset.entity.TblPropEntity;
import com.sh.data.engine.repository.dao.datadev.entity.DatadevJobEntity;
import com.sh.data.engine.repository.dao.integration.datasource.entity.DataSourceEntity;
import gudusoft.gsqlparser.EDbVendor;
import gudusoft.gsqlparser.dlineage.DataFlowAnalyzer;
import gudusoft.gsqlparser.dlineage.dataflow.model.RelationshipType;
import gudusoft.gsqlparser.dlineage.dataflow.model.SqlInfo;
import gudusoft.gsqlparser.dlineage.dataflow.model.xml.dataflow;
import gudusoft.gsqlparser.dlineage.dataflow.model.xml.relationship;
import gudusoft.gsqlparser.dlineage.metadata.Schema;
import gudusoft.gsqlparser.dlineage.metadata.Server;
import gudusoft.gsqlparser.dlineage.metadata.Sqlflow;
import gudusoft.gsqlparser.dlineage.metadata.Table;
import gudusoft.gsqlparser.dlineage.util.DataflowUtility;
import gudusoft.gsqlparser.dlineage.util.Pair;
import gudusoft.gsqlparser.sqlenv.ESQLDataObjectType;
import gudusoft.gsqlparser.sqlenv.TSQLEnv;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

/**
 * @Author: zigui.zdf @Date: 2022/3/14 16:48:40 @Description:
 */
@Service
@Slf4j
public class LineageServiceImpl extends ServiceImpl<LineageMapper, LineageEntity>
    implements LineageService {

    @Autowired
    private TableService tableService;

    @Autowired
    private TblPropService tblPropService;

    @Lazy
    @Autowired
    private TableProductService tableProductService;

    @Lazy
    @Autowired
    private DatadevJobService datadevJobService;

    @Lazy
    @Autowired
    private DataSourceService dataSourceService;

    @Value("${data.engine.datadevSelectMaxSize:10000}")
    private Integer datadevSelectMaxSize;

    @Override
    public List<LineageDomain> analyseSqlLineage(String sql, Database database, Long projectId) {
        List<LineageDomain> domains = new ArrayList<>();

        String schema = null;
        DataSourceDetailDomain dataSourceDomain =
            dataSourceService.getDataSourceDetailByProjectId(projectId, false);
        String dsType = dataSourceDomain.getDsType();
        if (DSType.isRdbms(dsType)) {
            schema = dataSourceDomain.getRdbmsConfig().getSchema();
        }
        if (StringUtils.isBlank(sql)) {
            return domains;
        }
        String time = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
        String lineage = String.format("[%s] lineage sql : %s", time, sql);
        log.info(lineage);
        DbType dbType;
        switch (database) {
            case HIVE:
                dbType = JdbcConstants.HIVE;
                break;
            case POSTGRESQL:
                dbType = JdbcConstants.POSTGRESQL;
                break;
            case MYSQL:
                dbType = JdbcConstants.MYSQL;
                break;
            case ORACLE:
                dbType = JdbcConstants.ORACLE;
                break;
            case TIDB:
                dbType = JdbcConstants.MYSQL;
                break;
            case KINGBASE8:
                dbType = JdbcConstants.KINGBASE;
                break;
            case SAP:
                dbType = DbType.valueOf("sapdb");
                break;
            case DM:
                dbType = JdbcConstants.DM;
                break;
            default:
                throw new RuntimeException("不支持的数据源类型");
        }

        List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, dbType);

        for (SQLStatement sqlStatement : sqlStatements) {
            SchemaStatVisitor schemaStatVisitor = SQLUtils.createSchemaStatVisitor(dbType);
            sqlStatement.accept(schemaStatVisitor);
            Map<TableStat.Name, TableStat> tables = schemaStatVisitor.getTables();
            Collection<TableStat.Column> columns = schemaStatVisitor.getColumns();

            if (Objects.isNull(tables)) {
                continue;
            }

            Map<String, List<String>> targetTableInfoMap = new HashMap<>();
            Map<String, List<String>> sourceTableInfoMap = new HashMap<>();

            tables.forEach(
                ((name, tableStat) -> {
                    if (tableStat.getCreateCount() > 0 || tableStat.getInsertCount() > 0) {
                        final List<String> columnList =
                            columns.stream()
                                .filter(
                                    column ->
                                        Objects.equals(
                                            column.getTable().toLowerCase(), name.getName().toLowerCase()))
                                .map(TableStat.Column::getName)
                                .collect(Collectors.toList());
                        targetTableInfoMap.put(name.getName(), columnList);

                    } else if (tableStat.getSelectCount() > 0) {
                        final List<String> columnList =
                            columns.stream()
                                .filter(
                                    column ->
                                        Objects.equals(
                                            column.getTable().toLowerCase(), name.getName().toLowerCase()))
                                .map(TableStat.Column::getName)
                                .collect(Collectors.toList());
                        sourceTableInfoMap.put(name.getName(), columnList);
                    }
                }));

            // all empty
            if (targetTableInfoMap.isEmpty() && sourceTableInfoMap.isEmpty()) {
                continue;
            }

            QueryTableParam queryTableParam = new QueryTableParam();
            List<TableInfoBizDomain> tableList = tableService.getTableList(projectId, queryTableParam);
            Map<String, TableInfoBizDomain> tableInfoBizDomainMap = new HashMap<>(20);
            if (Database.SAP.name().equals(database.name())) {
                tableList.stream()
                    .collect(Collectors.toMap(x -> x.getSchema() + "." + x.getTableName(), x -> x));
            } else {
                tableInfoBizDomainMap =
                    tableList.stream().collect(Collectors.toMap(x -> x.getTableName(), x -> x));
            }

            // target is not empty.
            if (sourceTableInfoMap.isEmpty()) {
                Map<String, TableInfoBizDomain> finalTableInfoBizDomainMap = tableInfoBizDomainMap;
                String finalSchema = schema;
                targetTableInfoMap.forEach(
                    (tableName, columnList) -> {
                        TableInfoBizDomain targetTableDomain = finalTableInfoBizDomainMap.get(tableName);
                        if (null == targetTableDomain) {
                            return;
                        }
                        if (StringUtils.isNotBlank(finalSchema) && !tableName.startsWith(finalSchema)) {
                            tableName = finalSchema + "." + tableName;
                        }
                        LineageDomain lineageDomain = new LineageDomain();
                        lineageDomain.setTargetTable(tableName);
                        lineageDomain.setTargetFields(columnList);
                        lineageDomain.setTargetTblId(targetTableDomain.getTblId());
                        domains.add(lineageDomain);
                    });
                continue;
            }
            // all is not empty
            Map<String, TableInfoBizDomain> finalTableInfoBizDomainMap1 = tableInfoBizDomainMap;
            String finalSchema = schema;
            targetTableInfoMap.forEach(
                (tableName, columnList) -> {
                    sourceTableInfoMap.forEach(
                        (sourceTableName, sourceColumnList) -> {
                            String targetTableName = tableName;
                            if (StringUtils.isNotBlank(finalSchema)
                                && !targetTableName.startsWith(finalSchema)
                                && !targetTableName.contains(".")) {
                                targetTableName = finalSchema + "." + targetTableName;
                            }

                            if (StringUtils.isNotBlank(finalSchema)
                                && !sourceTableName.startsWith(finalSchema)
                                && !sourceTableName.contains(".")) {
                                sourceTableName = finalSchema + "." + sourceTableName;
                            }
                            LineageDomain lineageDomain = new LineageDomain();
                            lineageDomain.setTargetTable(targetTableName);
                            lineageDomain.setTargetFields(columnList);
                            lineageDomain.setSourceTable(sourceTableName);
                            lineageDomain.setSourceFields(sourceColumnList);
                            final TableInfoBizDomain targetTableInfo =
                                finalTableInfoBizDomainMap1.get(targetTableName);
                            final TableInfoBizDomain sourceTableInfo =
                                finalTableInfoBizDomainMap1.get(sourceTableName);
                            if (null == targetTableInfo || null == sourceTableInfo) {
                                return;
                            }
                            lineageDomain.setTargetTblId(targetTableInfo.getTblId());
                            lineageDomain.setSourceTblId(sourceTableInfo.getTblId());

                            domains.add(lineageDomain);
                        });
                });
        }

        return domains;
    }

    @Override
    public void analyseAndInsertSqlLineage(
        String sql, Database database, Long projectId, DatadevJobEntity jobEntity) {
        /** 工作流任务的产出信息记录 */
        final List<LineageDomain> domainList = this.analyseSqlLineage(sql, database, projectId);
        if (null != jobEntity && Objects.nonNull(jobEntity.getTaskFlowJobId())) {
            DatadevJobEntity offlineDevJob = datadevJobService.getById(jobEntity.getTaskFlowJobId());
            List<TableProductEntity> tableProductEntities =
                domainList.stream()
                    .map(
                        e -> {
                            TableProductEntity tableProductEntity = new TableProductEntity();
                            tableProductEntity.setJobId(jobEntity.getId());
                            tableProductEntity.setTblId(e.getTargetTblId());
                            tableProductEntity.setProjectId(jobEntity.getProjectId());
                            tableProductEntity.setSubTaskId(jobEntity.getNodeId());
                            tableProductEntity.setTaskFlowId(offlineDevJob.getNodeId());
                            return tableProductEntity;
                        })
                    .collect(Collectors.toList());
            tableProductService.insetTableProduct(tableProductEntities);
        }

        /** 血缘关系记录 */
        List<LineageDomain> domains =
            domainList.stream()
                .filter(
                    e ->
                        (StringUtils.isNotBlank(e.getSourceTable())
                            && StringUtils.isNotBlank(e.getTargetTable())))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(domains)) {
            return;
        }
        List<LineageEntity> addList = new ArrayList<>();

        final List<Long> targetTblIds =
            domains.stream().map(LineageDomain::getTargetTblId).collect(Collectors.toList());
        LambdaQueryWrapper<LineageEntity> lambdaQueryWrapper =
            new LambdaQueryWrapper<LineageEntity>().in(LineageEntity::getTargetTblId, targetTblIds);
        final List<LineageEntity> entityList = this.list(lambdaQueryWrapper);
        final Map<String, LineageEntity> lineageEntityMap =
            entityList.stream()
                .collect(Collectors.toMap(x -> x.getTargetTblId() + "_" + x.getSourceTblId(), x -> x));

        for (LineageDomain domain : domains) {
            final long targetTblId = domain.getTargetTblId();
            final long sourceTblId = domain.getSourceTblId();

            String key = targetTblId + "_" + sourceTblId;

            if (!lineageEntityMap.containsKey(key)) {
                LineageEntity entity = new LineageEntity();
                entity.setProjectId(projectId);
                entity.setTargetTblId(targetTblId);
                entity.setSourceTblId(sourceTblId);
                addList.add(entity);
            }
        }

        if (!addList.isEmpty()) {
            this.saveBatch(addList);
        }
    }

    @Override
    public String analyCreatetable(String sql, Database database) {
        if (StringUtils.isBlank(sql)) {
            return null;
        }
        DbType dbType = null;
        switch (database) {
            case HIVE:
                dbType = JdbcConstants.HIVE;
                break;
            case POSTGRESQL:
                dbType = JdbcConstants.POSTGRESQL;
                break;
            case MYSQL:
                dbType = JdbcConstants.MYSQL;
                break;
            case ORACLE:
                dbType = JdbcConstants.ORACLE;
                break;
            default:
                break;
        }
        StringBuilder sb = new StringBuilder();
        if (Database.SAP.equals(database)) {
            String createTable = SqlParserUtil.getCreateTableAndView(sql);
            return createTable;
        }

        List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, dbType);
        for (SQLStatement sqlStatement : sqlStatements) {
            SchemaStatVisitor schemaStatVisitor = SQLUtils.createSchemaStatVisitor(dbType);
            sqlStatement.accept(schemaStatVisitor);
            Map<TableStat.Name, TableStat> tables = schemaStatVisitor.getTables();

            if (Objects.isNull(tables)) {
                continue;
            }
            tables.forEach(
                (table, tableOperator) -> {
                    if (tableOperator.getCreateCount() > 0) {
                        sb.append(table);
                    }
                });
        }
        return sb.toString();
    }

    @Override
    public void analySapLineageAndInsert(String sql, Long projectId, DatadevJobEntity jobEntity) {
        Map<String, String> consanguinityForSap = SqlParserUtil.getConsanguinityForSap(sql);
        String source = consanguinityForSap.get("source");
        String target = consanguinityForSap.get("target");
        TblPropEntity targetTbl = tblPropService.getTblPropByTblName(projectId, target);

        if (null == targetTbl) {
            log.error("目标表：{}不存在", target);
            return;
        }

        List<LineageEntity> res = Lists.newArrayList();
        if (StringUtils.isNotBlank(source) && StringUtils.isNotBlank(target)) {
            String[] split = source.split(",");
            for (String s : split) {
                TblPropEntity sourceTable = tblPropService.getTblPropByTblName(projectId, s);
                if (null == sourceTable) {
                    continue;
                }
                QueryTableParam queryTableParam = new QueryTableParam();
                queryTableParam.setTableNamePrefix(s);
                LineageEntity lineageEntity = new LineageEntity();
                lineageEntity.setProjectId(projectId);
                lineageEntity.setTargetTblId(targetTbl.getTblId());
                lineageEntity.setSourceTblId(sourceTable.getTblId());
                res.add(lineageEntity);
            }
        }
        if (!res.isEmpty()) {
            this.saveBatch(res);
        }
    }

    @Override
    public Map<String, Set<Long>> analyseSqlUsedAuthority(
        String sql, Database database, Long projectId) {
        DataSourceEntity systemDataSourceDetail =
            dataSourceService.getSystemDataSourceDetail(projectId);
        String schema = null;
        if (Objects.nonNull(systemDataSourceDetail)
            && Objects.nonNull(systemDataSourceDetail.getRdbmsConfig())) {
            schema = systemDataSourceDetail.getRdbmsConfig().getSchema();
        }
        Map<String, Set<Long>> res = Maps.newHashMap();
        if (StringUtils.isBlank(sql)) {
            return res;
        }
        String time = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");
        String lineage = String.format("[%s] lineage sql : %s", time, sql);
        log.info(lineage);
        DbType dbType;
        switch (database) {
            case HIVE:
                dbType = JdbcConstants.HIVE;
                break;
            case POSTGRESQL:
                dbType = JdbcConstants.POSTGRESQL;
                break;
            case MYSQL:
                dbType = JdbcConstants.MYSQL;
                break;
            case ORACLE:
                dbType = JdbcConstants.ORACLE;
                break;
            case TIDB:
                dbType = JdbcConstants.MYSQL;
                break;
            default:
                throw new RuntimeException("不支持的数据源类型");
        }
        final List<TableInfoBizDomain> tableList = tableService.getTableList(projectId, null);
        Map<String, Long> stringLongMap =
            tableList.stream().collect(Collectors.toMap(x -> x.getTableName(), x -> x.getTblId()));
        Set<Long> readTable = Sets.newHashSet();
        Set<Long> writeTable = Sets.newHashSet();
        List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, dbType);
        for (SQLStatement sqlStatement : sqlStatements) {
            SchemaStatVisitor schemaStatVisitor = SQLUtils.createSchemaStatVisitor(dbType);
            sqlStatement.accept(schemaStatVisitor);
            Map<TableStat.Name, TableStat> tables = schemaStatVisitor.getTables();
            String finalSchema = schema;
            tables.forEach(
                (name, state) -> {
                    if (state.getSelectCount() > 0
                        || state.getAnalyzeCount() > 0
                        || state.getReferencedCount() > 0) {
                        String tableName = name.getName();
                        if (!tableName.contains(".")
                            && DSType.hasSchema(systemDataSourceDetail.getDsType())) {
                            tableName = finalSchema + "." + tableName;
                        }
                        Long tblId = stringLongMap.get(tableName);
                        readTable.add(tblId);
                    } else if (state.getCreateCount() > 0) {
                        // 不做处理
                    } else {
                        Long tblId = stringLongMap.get(name.getName());
                        writeTable.add(tblId);
                    }
                });
        }

        res.put("read", readTable);
        res.put("write", writeTable);
        return res;
    }

    @Override
    public LineageMapDomain getLineage(Long tblId, Long projectId) {

        // 查询targetId 或者 sourceId 是tblId 的数据
        LambdaQueryWrapper<LineageEntity> and =
            new LambdaQueryWrapper<LineageEntity>()
                .eq(LineageEntity::getProjectId, projectId)
                .and(
                    e ->
                        e.eq(LineageEntity::getSourceTblId, tblId)
                            .or()
                            .eq(LineageEntity::getTargetTblId, tblId));
        List<LineageEntity> lineageEntities = this.list(and);
        List<LineageDomain> lineageDomains =
            ConvertUtil.copyProperties(lineageEntities, LineageDomain.class);
        if (CollectionUtils.isEmpty(lineageDomains)) {
            // 如果查询不到血缘数据，返回该表这个节点
            LineageMapDomain.TableNode tableNode = new LineageMapDomain.TableNode();
            tableNode.setTblIdStr(tblId.toString());
            // 拼接入表名
            TblPropEntity tblPropByTblId = tblPropService.getTblPropByTblId(projectId, tblId);
            if (tblPropByTblId != null) {
                tableNode.setTblName(tblPropByTblId.getTableName());
                tableNode.setTblTitle(tblPropByTblId.getTableName().split("_")[0].toUpperCase());
            }
            LineageMapDomain lineageMapDomain = new LineageMapDomain();
            List<LineageMapDomain.TableNode> tableNodes = new ArrayList<>();
            tableNodes.add(tableNode);
            lineageMapDomain.setTableNodes(tableNodes);
            return lineageMapDomain;
        }

        for (LineageDomain lineageDomain : lineageDomains) {
            // 拼接入表名
            TblPropEntity tblPropByTblIdSource =
                tblPropService.getTblPropByTblId(projectId, lineageDomain.getSourceTblId());
            if (tblPropByTblIdSource != null) {
                lineageDomain.setSourceTable(tblPropByTblIdSource.getTableName());
            }
            TblPropEntity tblPropByTblIdTarget =
                tblPropService.getTblPropByTblId(projectId, lineageDomain.getTargetTblId());
            if (tblPropByTblIdTarget != null) {
                lineageDomain.setTargetTable(tblPropByTblIdTarget.getTableName());
            }
            lineageDomain.setSourceTblIdStr(String.valueOf(lineageDomain.getSourceTblId()));
            lineageDomain.setTargetTblIdStr(String.valueOf(lineageDomain.getTargetTblId()));
        }

        // 找到不重复的表节点
        Set<String> tblIdStrSet = new HashSet<>();
        for (LineageDomain lineageDomain : lineageDomains) {
            tblIdStrSet.add(lineageDomain.getSourceTblIdStr());
            tblIdStrSet.add(lineageDomain.getTargetTblIdStr());
        }
        List<LineageMapDomain.TableNode> tableNodes = new ArrayList<>();
        for (String tblIdStr : tblIdStrSet) {
            LineageMapDomain.TableNode tableNode = new LineageMapDomain.TableNode();
            tableNode.setTblIdStr(tblIdStr);
            // 拼接入表名
            TblPropEntity tblPropByTblId =
                tblPropService.getTblPropByTblId(projectId, Long.valueOf(tblIdStr));
            if (tblPropByTblId != null) {
                tableNode.setTblName(tblPropByTblId.getTableName());
                tableNode.setTblTitle(tblPropByTblId.getTableName().split("_")[0].toUpperCase());
            }
            tableNodes.add(tableNode);
        }

        LineageMapDomain lineageMapDomain = new LineageMapDomain();
        lineageMapDomain.setLineageDomains(lineageDomains);
        lineageMapDomain.setTableNodes(tableNodes);

        return lineageMapDomain;
    }

    @Override
    public String checkIsSelectSql(String sql, Database database) {
        String executeSQL = null;
        Integer datadevSelectMaxSize = this.datadevSelectMaxSize;
        EDbVendor dbType;
        switch (database) {
            case SAP:
                dbType = EDbVendor.dbvhana;
                break;
            case HIVE:
                dbType = EDbVendor.dbvhive;
                break;
            case POSTGRESQL:
                dbType = EDbVendor.dbvpostgresql;
                break;
            case MYSQL:
                dbType = EDbVendor.dbvpostgresql;
                break;
            case ORACLE:
                dbType = EDbVendor.dbvoracle;
                break;
            case TIDB:
                dbType = EDbVendor.dbvpostgresql;
                break;
            case DM:
                dbType = EDbVendor.dbvoracle;
                break;
            case KINGBASE8:
                dbType = EDbVendor.dbvpostgresql;
                break;
            default:
                throw new RuntimeException("不支持的数据源类型");
        }

        boolean isSelectSQl = SqlParserUtil.checkIsSelectSQl(sql, dbType);
        if (isSelectSQl) {
            StringBuilder sb = new StringBuilder();
            sb.append("select * from ( ");
            sb.append(sql);
            sb.append(" ) as t");
            sb.append(" limit ");
            sb.append(datadevSelectMaxSize);
            executeSQL = sb.toString();
            return executeSQL;
        }
        return null;
    }

    @Override
    public List<FieldInfo> getFieldInfoBySQLScrip(String sql) {

        Long projectId = ServletUtils.getProjectId();
        DataSourceDomain dataSourceDomain = dataSourceService.getSystemDataSourceByProjectId(projectId);
        // 判断系统数据源类型
        String dsType = dataSourceDomain.getDsType();

        Database database = Database.from("PostgreSQL");
        DbType dbType;
        switch (database) {
            case HIVE:
                dbType = JdbcConstants.HIVE;
                break;
            case POSTGRESQL:
                dbType = JdbcConstants.POSTGRESQL;
                break;
            case MYSQL:
                dbType = JdbcConstants.MYSQL;
                break;
            case ORACLE:
                dbType = JdbcConstants.ORACLE;
                break;
            case TIDB:
                dbType = JdbcConstants.MYSQL;
                break;
            case DM:
                dbType = JdbcConstants.DM;
                break;
            default:
                throw new RuntimeException("不支持的数据源类型");
        }

        List<FieldInfo> r1 = Lists.newArrayList();
        SQLStatementParser sqlStatementParser = SQLParserUtils.createSQLStatementParser(sql, dbType);
        SQLCreateTableStatement sqlCreateTableStatement = sqlStatementParser.parseCreateTable();
        List<SQLObject> sqlObjects = sqlCreateTableStatement.getChildren();
        try {
            for (SQLObject sqlObject : sqlObjects) {
                if (sqlObject instanceof SQLColumnDefinition) {
                    SQLColumnDefinition columnDefinition = ((SQLColumnDefinition) sqlObject);
                    FieldInfo fieldInfo = new FieldInfo();
                    fieldInfo.setFieldName(columnDefinition.getNameAsString().replaceAll("\"", ""));
                    String metaType = columnDefinition.getDataType().getName();
                    List<SQLExpr> arguments = columnDefinition.getDataType().getArguments();
                    if (!CollectionUtils.isEmpty(arguments)) {
                        metaType =
                            metaType + "(" + ((SQLIntegerExpr) arguments.get(0)).getNumber().toString() + ")";
                    }
                    fieldInfo.setFieldType(metaType);
                    if (columnDefinition.getComment() != null) {
                        fieldInfo.setComment((String) ((SQLCharExpr) columnDefinition.getComment()).getValue());
                    }
                    if (columnDefinition.isPrimaryKey()) {
                        fieldInfo.setPk(true);
                    }
                    r1.add(fieldInfo);
                }
            }
        } catch (Exception e) {
            throw new BusinessException("解析SQL失败，请检查SQL语法规则");
        }
        return r1;
    }

    @Override
    public boolean checkSQLUpdateMd(String sql, Database database) {
        if (Database.SAP.equals(database)) {
            boolean r1 = SqlParserUtil.checkUpdateMdSQL(sql);
            return r1;
        }
        DbType dbType;
        switch (database) {
            case HIVE:
                dbType = JdbcConstants.HIVE;
                break;
            case POSTGRESQL:
                dbType = JdbcConstants.POSTGRESQL;
                break;
            case MYSQL:
                dbType = JdbcConstants.MYSQL;
                break;
            case ORACLE:
                dbType = JdbcConstants.ORACLE;
                break;
            case TIDB:
                dbType = JdbcConstants.MYSQL;
                break;
            case DM:
                dbType = JdbcConstants.DM;
                break;
            default:
                throw new RuntimeException("不支持的数据源类型");
        }
        List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, dbType);
        AtomicBoolean flag = new AtomicBoolean(false);
        for (SQLStatement sqlStatement : sqlStatements) {
            SchemaStatVisitor schemaStatVisitor = SQLUtils.createSchemaStatVisitor(dbType);
            sqlStatement.accept(schemaStatVisitor);
            Map<TableStat.Name, TableStat> tables = schemaStatVisitor.getTables();
            tables.forEach(
                (name, state) -> {
                    if (state.getAlterCount() > 0 || state.getUpdateCount() > 0) {
                        if (name.getName().startsWith("md_")) {
                            flag.set(true);
                        }
                    }
                });
        }

        return flag.get();
    }

    @Override
    public TableLineageDomain getLineageDetail(Long tblId, Long projectId) {
        TableLineageDomain lineageDomain = new TableLineageDomain();
        Set<TableNode> nodeList = Sets.newHashSet();
        Set<Relation> relationList = Sets.newHashSet();
        TableNode tableNode = new TableNode();
        TblPropEntity tblPropByTblId = tblPropService.getTblPropByTblId(projectId, tblId);
        tableNode.setIsOwner(1);
        tableNode.setTblId(tblId);
        tableNode.setTblName(tblPropByTblId.getTableName());
        nodeList.add(tableNode);
        lineageDomain.setNodeList(nodeList);
        lineageDomain.setRelationList(relationList);
        fixSourceAndTargetLineage(lineageDomain, true, tblPropByTblId, Lists.newArrayList());
        fixSourceAndTargetLineage(lineageDomain, false, tblPropByTblId, Lists.newArrayList());

        return lineageDomain;
    }

    private LogRecord initLogRecord(String dbVendor, String logSHA256,
                                    String cacheKey) {

        LogRecord logRecord = new LogRecord();
        Date date = new Date();
        logRecord.setDate((new SimpleDateFormat("yyyy-MM-dd")).format(date));
        logRecord.setTime((new SimpleDateFormat("HH:mm:ss")).format(date));
        logRecord.setIp("ip");
        logRecord.setBrowser("broswer");
        logRecord.setOs("os");
        logRecord.setTimeUsed(System.currentTimeMillis());
        return logRecord;
    }

    protected SqlInfo[] convertSQL(String json, boolean extractGrabit, boolean includeMetadata) {
        List<SqlInfo> sqlInfos = new ArrayList<>();
        SqlInfo info = new SqlInfo();
        info.setSql(json);
        info.setFileName("fileName");
        info.setFilePath("filePath");
        info.setOriginIndex(0);
        sqlInfos.add(info);
        return sqlInfos.<SqlInfo>toArray(new SqlInfo[0]);
    }

    private void filterRelation(dataflow dataflow1, String showRelationType) {
        List<RelationshipType> relationshipTypes = (List<RelationshipType>) Arrays.<String>asList(
            showRelationType.split(",")).stream().map(t -> RelationshipType.valueOf(t.trim())).collect(
            Collectors.toList());
        if (relationshipTypes.contains(RelationshipType.join) && !relationshipTypes.contains(
            RelationshipType.fdd)) {
            relationshipTypes.add(RelationshipType.fdd);
        }
        if (dataflow1.getRelationships() != null) {
            List<relationship> relationships = (List<relationship>) dataflow1.getRelationships().stream()
                .filter(t -> relationshipTypes.contains(RelationshipType.valueOf(t.getType())))
                .collect(Collectors.toList());
            dataflow1.setRelationships(relationships);
        }
    }

    private Set<relationship> getAllRelations(Map<String, Set<relationship>> relationshipMap) {
        Set<relationship> relationships = new LinkedHashSet<>();
        if (relationshipMap != null) {
            for (Set<relationship> value : relationshipMap.values()) {
                if (value != null) {
                    relationships.addAll(value);
                }
            }
        }
        return relationships;
    }

    private JSONObject getGraphResult(boolean isReturnModel, String dbvendor, String showRelationType,
                                      boolean showLinkOnly, boolean hideColumn, boolean ignoreFunction, String logSHA256,
                                      JSONObject summaryInfo, dataflow dataflow1, Collection<relationship> relationships,
                                      boolean simpleOutput, boolean ignoreRecordSet, boolean containGraphML, boolean tableLevel,
                                      boolean normalizeIdentifier, boolean showTransform, String jobId, String columnLevel,
                                      String serverName, String databaseName, String schemaName, String tableName,
                                      SqlflowService sqlflowService) {
        EDbVendor vendor = EDbVendor.valueOf(dbvendor);

        if (relationships != null) {
            dataflow1.setRelationships(new ArrayList<>(relationships));
        } else {
            dataflow1.setRelationships(Collections.EMPTY_LIST);
        }
        if ((simpleOutput || ignoreRecordSet) && !showRelationType.contains(
            RelationshipType.er.name())) {
            DataFlowAnalyzer analyzer = null;
            try {
                analyzer = new DataFlowAnalyzer("", EDbVendor.valueOf(dbvendor), true);
                analyzer.setTransform(showTransform);
                if (showTransform) {
                    analyzer.setTransformCoordinate(true);
                }
                dataflow1 = analyzer.getSimpleDataflow(dataflow1, simpleOutput,
                    Arrays.asList(showRelationType.split("\\s*,\\s*")));
            } catch (Exception e) {

            } finally {
                if (analyzer != null) {
                    analyzer.dispose();
                }
            }
        }
        dataflow originDataflow = dataflow1;
        if (!org.springframework.util.StringUtils.isEmpty(jobId)) {
            if (org.springframework.util.StringUtils.isEmpty(columnLevel) || "false".equals(columnLevel)) {
                dataflow1 = DataflowUtility.convertToTableLevelDataflow(dataflow1);
            }
        } else if ("false".equals(columnLevel)) {
            dataflow1 = DataflowUtility.convertToTableLevelDataflow(dataflow1);
        }

        JSONObject result = sqlflowService.generateSqlflowGraphByDataFlowWithCache(originDataflow,
            dataflow1, dbvendor, showRelationType, showLinkOnly, hideColumn, ignoreFunction,
            containGraphML, normalizeIdentifier, jobId, serverName, databaseName, schemaName,
            tableName);
        return getNonSummaryResult(result, isReturnModel, false, originDataflow, dbvendor, tableLevel,
            normalizeIdentifier, jobId, sqlflowService);
    }


    @Override
    public String generateSqlflowGraph(String sql, String database, String schema, String table,
                                       String column, boolean isReturnModel, String dbvendor, String showRelationType,
                                       boolean simpleOutput, boolean ignoreRecordSet,
                                       boolean treatArgumentsInCountFunctionAsDirectDataflow, boolean showConstantTable,
                                       boolean showTransform, boolean showLinkOnly, boolean hideColumn, boolean ignoreFunction,
                                       boolean normalizeIdentifier, String jobId, String columnLevel, boolean parallel,
                                       String sqlHash, boolean containGraphML, boolean leftMostTable, boolean getFileContent,
                                       boolean forceTableLevel, String defaultServer, String defaultDatabase, String defaultSchema) {
        long startTime = System.currentTimeMillis();
        LogRecord logRecord = initLogRecord(dbvendor, "logSHA256", "cacheKey");
        logRecord.setType(showRelationType);
        EDbVendor vendor = EDbVendor.valueOf(dbvendor);
        SqlflowService sqlflowService = new SqlflowService();
        dataflow dataflow = null;
        String sqltext = sql;
        SqlInfo[] sqltexts = convertSQL(sqltext, true, true);
        sqltext = null;
        TSQLEnv sqlEnv = null;
        Pair<dataflow, String> dataflowResult = sqlflowService.generateDataflowWithCache(null, sqltexts,
            dbvendor, showRelationType, false, false, treatArgumentsInCountFunctionAsDirectDataflow,
            showConstantTable, showTransform, sqlHash, parallel, logRecord, normalizeIdentifier,
            defaultServer, defaultDatabase, defaultSchema);
        dataflow = (dataflow) dataflowResult.first;
        dataflow dataflowCopy = DataflowUtility.cloneDataflow(dataflow);
        dataflow = dataflowCopy;

        filterRelation(dataflow, showRelationType);
        JSONObject summaryInfo = sqlflowService.getSummaryInfo(vendor, dataflow, database, schema,
            table, column);
        if (dataflow.getRelationships() != null) {
            Set<relationship> databaseRelations, schemaRelations;
            Map<String, Set<relationship>> databaseRelationMap = sqlflowService.getDataBaseRelationMap(
                vendor, dataflow);
            if (database != null) {
                if ("DEFAULT".equalsIgnoreCase(database)) {
                    databaseRelations = databaseRelationMap.get(null);
                } else {
                    databaseRelations = databaseRelationMap.get(
                        SQLUtil.getIdentifierNormalName(vendor, database, ESQLDataObjectType.dotCatalog));
                }
            } else {
                databaseRelations = getAllRelations(databaseRelationMap);
            }
            Map<String, Set<relationship>> schemaRelationMap = sqlflowService.getSchemaRelationMap(vendor,
                dataflow, databaseRelations);
            if (schema != null) {
                if ("DEFAULT".equalsIgnoreCase(schema)) {
                    schemaRelations = schemaRelationMap.get(null);
                } else {
                    schemaRelations = schemaRelationMap.get(
                        SQLUtil.getIdentifierNormalName(vendor, schema, ESQLDataObjectType.dotSchema));
                }
            } else {
                schemaRelations = getAllRelations(schemaRelationMap);
            }
            if (contains(new String[]{table})) {
                Map<String, Set<relationship>> tableRelationMap = sqlflowService.getTableRelationMap(vendor,
                    dataflow, schemaRelations);
                if (!TSQLEnv.supportSchema(vendor) && "DEFAULT".equals(database)) {
                    database = schema;
                }
                Set<relationship> tableRelations = tableRelationMap.get(
                    SQLUtil.getIdentifierNormalTableName(vendor,
                        SQLUtil.getTableFullName(vendor, database, schema, table)));
                if (contains(new String[]{column})) {
                    Map<String, Set<relationship>> columnRelationMap = sqlflowService.getColumnRelationMap(
                        vendor, dataflow, tableRelations);
                    tableRelations = columnRelationMap.get(
                        SQLUtil.getIdentifierNormalColumnName(vendor, column));
                }
                dataflow.setRelationships(
                    (tableRelations == null) ? Collections.EMPTY_LIST : new ArrayList<>(tableRelations));
                dataflow dataflow1 = dataflow;

                dataflow1 = dataflow;
                dataflow = DataflowUtility.convertToTableLevelDataflow(dataflow);
                ignoreFunction = true;
                JSONObject jSONObject3 = sqlflowService.generateSqlflowGraphByDataFlowWithCache(dataflow1,
                    dataflow, dbvendor, showRelationType, showLinkOnly, hideColumn, ignoreFunction,
                    containGraphML, normalizeIdentifier, jobId, null, database, schema, table);
                jSONObject3 = getNonSummaryResult(jSONObject3, isReturnModel, false, dataflow1, dbvendor,
                    false, normalizeIdentifier, jobId, sqlflowService);

                return jSONObject3.toJSONString();
            }
            JSONObject jSONObject2 = getGraphResult(isReturnModel, dbvendor, showRelationType,
                showLinkOnly, hideColumn, ignoreFunction, "logSHA256", summaryInfo, dataflow,
                schemaRelations, simpleOutput, ignoreRecordSet, containGraphML, false,
                normalizeIdentifier, showTransform, jobId, columnLevel, null, database, schema, table,
                sqlflowService);
            System.out.println(jSONObject2.toJSONString());
            return jSONObject2.toJSONString();
        }
        return "null";
    }

    private JSONObject getNonSummaryResult(JSONObject result, boolean isReturnModel,
                                           boolean forceSwitchIgnoreMode, dataflow dataflow1, String dbvendor, boolean tableLevel,
                                           boolean normalizeIdentifier, String jobId, SqlflowService sqlflowService) {
        JSONObject data = result.getJSONObject("data");
        if (data != null) {
            if (isReturnModel) {
                if (!data.containsKey("sqlflow")) {
                    DataFlow model = SqlflowService.getSqlflowModel(EDbVendor.valueOf(dbvendor), dataflow1,
                        normalizeIdentifier, false);
                    data.put("sqlflow", model);
                }
            } else {
                DataFlow model = (DataFlow) data.get("sqlflow");
                Set<String> dbObjIds = (Set<String>) data.remove("dbObjIds");
                if (model.getDbobjs() != null) {
                    Sqlflow sqlflow = model.getDbobjs();
                    if (sqlflow.getServers() != null) {
                        for (Server server : sqlflow.getServers()) {
                            if (server.isSupportsCatalogs() && server.isSupportsSchemas()) {
                                if (server.getDatabases() == null) {
                                    continue;
                                }
                                for (gudusoft.gsqlparser.dlineage.metadata.Database database : server.getDatabases()) {
                                    if (database.getSchemas() == null) {
                                        continue;
                                    }
                                    for (Schema schema : database.getSchemas()) {
                                        if (schema.getTables() != null) {
                                            List<Table> tableList = new ArrayList<>();
                                            for (Table table : schema.getTables()) {
                                                if (dbObjIds.contains(table.getId())) {
                                                    tableList.add(table);
                                                }
                                            }
                                            schema.getTables().clear();
                                            schema.appendTables(tableList);
                                        }
                                        if (schema.getViews() != null) {
                                            List<Table> tableList = new ArrayList<>();
                                            for (Table table : schema.getViews()) {
                                                if (dbObjIds.contains(table.getId())) {
                                                    tableList.add(table);
                                                }
                                            }
                                            schema.getViews().clear();
                                            schema.appendViews(tableList);
                                        }
                                        if (schema.getOthers() != null) {
                                            List<Table> tableList = new ArrayList<>();
                                            for (Table table : schema.getOthers()) {
                                                if (dbObjIds.contains(table.getId())) {
                                                    tableList.add(table);
                                                }
                                            }
                                            schema.getOthers().clear();
                                            schema.appendOthers(tableList);
                                        }
                                    }
                                }
                                continue;
                            }
                            if (server.isSupportsCatalogs() && server.getDatabases() != null) {
                                for (gudusoft.gsqlparser.dlineage.metadata.Database database : server.getDatabases()) {
                                    if (database.getTables() != null) {
                                        List<Table> tableList = new ArrayList<>();
                                        for (Table table : database.getTables()) {
                                            if (dbObjIds.contains(table.getId())) {
                                                tableList.add(table);
                                            }
                                        }
                                        database.getTables().clear();
                                        database.appendTables(tableList);
                                    }
                                    if (database.getViews() != null) {
                                        List<Table> tableList = new ArrayList<>();
                                        for (Table table : database.getViews()) {
                                            if (dbObjIds.contains(table.getId())) {
                                                tableList.add(table);
                                            }
                                        }
                                        database.getViews().clear();
                                        database.appendViews(tableList);
                                    }
                                    if (database.getOthers() != null) {
                                        List<Table> tableList = new ArrayList<>();
                                        for (Table table : database.getOthers()) {
                                            if (dbObjIds.contains(table.getId())) {
                                                tableList.add(table);
                                            }
                                        }
                                        database.getOthers().clear();
                                        database.appendOthers(tableList);
                                    }
                                }
                                continue;
                            }
                            if (server.isSupportsSchemas() && server.getSchemas() != null) {
                                for (Schema schema : server.getSchemas()) {
                                    if (schema.getTables() != null) {
                                        List<Table> tableList = new ArrayList<>();
                                        for (Table table : schema.getTables()) {
                                            if (dbObjIds.contains(table.getId())) {
                                                tableList.add(table);
                                            }
                                        }
                                        schema.getTables().clear();
                                        schema.appendTables(tableList);
                                    }
                                    if (schema.getViews() != null) {
                                        List<Table> tableList = new ArrayList<>();
                                        for (Table table : schema.getViews()) {
                                            if (dbObjIds.contains(table.getId())) {
                                                tableList.add(table);
                                            }
                                        }
                                        schema.getViews().clear();
                                        schema.appendViews(tableList);
                                    }
                                    if (schema.getOthers() != null) {
                                        List<Table> tableList = new ArrayList<>();
                                        for (Table table : schema.getOthers()) {
                                            if (dbObjIds.contains(table.getId())) {
                                                tableList.add(table);
                                            }
                                        }
                                        schema.getOthers().clear();
                                        schema.appendOthers(tableList);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            data.remove("dbObjIds");
            if (forceSwitchIgnoreMode) {
                data.put("mode", "ignoreRecordSet");
            } else {
                data.put("mode", "global");
            }
            JSONObject summaryInfo = sqlflowService.getSummaryInfo(EDbVendor.valueOf(dbvendor), dataflow1,
                null, null, null, null);
            JSONObject graph = data.getJSONObject("graph");
            if (graph != null) {
                JSONObject relationships = graph.getJSONObject("relationshipIdMap");
                if (relationships != null) {
                    summaryInfo.put("relationship", Integer.valueOf(relationships.size()));
                }
            }
            data.put("summary", summaryInfo);
            result.put("data", data);
        }
        return result;
    }

    private boolean contains(String... args) {
        if (args == null || args.length == 0) {
            return false;
        }
        for (String arg : args) {
            if (!org.springframework.util.StringUtils.isEmpty(arg)) {
                return true;
            }
        }
        return false;
    }

    private void fixSourceAndTargetLineage(TableLineageDomain tableLineageDomain, boolean flag,
                                           TblPropEntity tblPropEntity, List<Long> usedTblProp) {
        Long projectId = tblPropEntity.getProjectId();
        Set<TableNode> nodeList = tableLineageDomain.getNodeList();
        Set<Relation> relationList = tableLineageDomain.getRelationList();
        Long tblId = tblPropEntity.getTblId();
        if (flag) {
            List<LineageEntity> sourceList = this.list(
                new LambdaQueryWrapper<>(LineageEntity.class).in(LineageEntity::getSourceTblId, tblId));
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(sourceList)) {
                for (LineageEntity lineageEntity : sourceList) {
                    long targetTblId = lineageEntity.getTargetTblId();
                    Relation relation = new Relation();
                    relation.setSourceTblName(tblPropEntity.getTableName());
                    relation.setSourceTblId(lineageEntity.getSourceTblId());
                    relation.setTargetTblId(targetTblId);
                    TblPropEntity tblProp = tblPropService.getTblPropByTblId(projectId, targetTblId);
                    relation.setTargetTblName(tblProp.getTableName());
                    TableNode targetNode = new TableNode();
                    targetNode.setIsOwner(0);
                    targetNode.setTblId(tblProp.getTblId());
                    targetNode.setTblName(tblProp.getTableName());
                    usedTblProp.add(tblProp.getTblId());
                    nodeList.add(targetNode);
                    relationList.add(relation);
                    fixSourceAndTargetLineage(tableLineageDomain, flag, tblProp, usedTblProp);
                }
            }
        } else {
            List<LineageEntity> tagetList = this.list(
                new LambdaQueryWrapper<>(LineageEntity.class).in(LineageEntity::getTargetTblId, tblId));
            if (org.apache.commons.collections.CollectionUtils.isNotEmpty(tagetList)) {
                for (LineageEntity lineageEntity : tagetList) {
                    long sourceTblId = lineageEntity.getSourceTblId();
                    long targetTblId = lineageEntity.getTargetTblId();
                    Relation relation = new Relation();
                    relation.setTargetTblName(tblPropEntity.getTableName());
                    relation.setSourceTblId(sourceTblId);
                    relation.setTargetTblId(targetTblId);
                    TblPropEntity tblProp = tblPropService.getTblPropByTblId(projectId, sourceTblId);
                    relation.setSourceTblName(tblProp.getTableName());
                    relationList.add(relation);
                    TableNode sourceNode = new TableNode();
                    sourceNode.setIsOwner(0);
                    sourceNode.setTblId(tblProp.getTblId());
                    usedTblProp.add(tblProp.getTblId());
                    sourceNode.setTblName(tblProp.getTableName());
                    nodeList.add(sourceNode);
                    fixSourceAndTargetLineage(tableLineageDomain, true, tblProp, usedTblProp);
                }
            }
        }
    }

    public static void main(String[] args) {

        //    String sql2  = "alter table m1d_member_table  add test1 varchar(40);";
        //    boolean b = checkSQLUpdateMd(sql2, Database.POSTGRESQL);
        //    System.out.println(b);
        String sql =
            "CREATE TABLE \"public\".\"tb_api_http\" (\n"
                + "  \"id\" int8 NOT NULL DEFAULT nextval('tb_api_http_id_seq'::regclass),\n"
                + "  \"create_time\" timestamp(6),\n"
                + "  \"creator_id\" int8,\n"
                + "  \"update_time\" timestamp(6),\n"
                + "  \"updater_id\" int8,\n"
                + "  \"row_state\" int2,\n"
                + "  \"project_id\" int8,\n"
                + "  \"xxl_job_id\" int8,\n"
                + "  \"task_name\" varchar(255),\n"
                + "  \"api_http_request\" text ,\n"
                + "  \"api_response\" text ,\n"
                + "  \"task_config_param\" text ,\n"
                + "  \"datax_job_script\" text ,\n"
                + "  \"task_status\" int2,\n"
                + "  \"start_time\" timestamp(6),\n"
                + "  \"end_time\" timestamp(6),\n"
                + "  CONSTRAINT \"tb_api_http_pkey\" PRIMARY KEY (\"id\")\n"
                + ")\n"
                + ";";

        String sql2 = "select * from tan";
        String selectSQL =
            "WITH start_time AS (\n"
                + "  -- 找到输入侧转速为 600 或 800 的数据行，并取该行时间作为起点\n"
                + "  SELECT CONCAT('2023-02-11 ',\"SJ\") time1\n"
                + "  FROM ods_cd_kqx_gcjxbsq_kzgl\n"
                + "  WHERE \"SRCZS\" IN ('600', '800')\n"
                + "  ORDER BY \"SRCZS\" DESC, time1\n"
                + "  LIMIT 1\n"
                + "), fifteen_data AS (\n"
                + "  -- 从起点时间 + 10 秒开始，取 15 条数据\n"
                + "  SELECT \n"
                + "  *\n"
                + "  FROM ods_cd_kqx_gcjxbsq_kzgl\n"
                + "  WHERE CONCAT('2023-02-11 ',\"SJ\")::timestamp >= (SELECT time1 FROM start_time)::timestamp + INTERVAL '10' SECOND\n"
                + "  ORDER BY \"SJ\"\n"
                + "  LIMIT 15\n"
                + ") \n"
                + "-- 将结果插入到记录表中\n"
                + "INSERT INTO ads_lab_cd_kqx_gcjxbsq_kzgl_source \n"
                + "SELECT \n"
                + "row_number() over(order by  max(\"SJ\") asc)as id,\n"
                + "round(AVG(\"SRCZS\"::integer)) AS A,-- 输入侧转速\n"
                + "round(AVG(\"SRCNJ\"::integer))  AS B,-- 输入侧扭矩\n"
                + "round(AVG(\"SRCZS\"::integer)*AVG(\"SRCNJ\"::integer)*3.14/30000) AS C, -- 输入功率\n"
                + "round(AVG(\"SRCZS\"::integer)*AVG(\"SRCNJ\"::integer)/9550*0.99-(AVG(\"SRCZS\"::integer)*2*3/1000*60*10*0.96))  -- 空载功率损失\n"
                + "FROM fifteen_data";

        String sql4 =
            "-- ********************************************************************--\n"
                + "-- author: admin\n"
                + "-- create time: Fri Jan 06 2023 14:55:06 GMT+0800 (中国标准时间)\n"
                + "-- ********************************************************************--\n"
                + "-- CREATE TABLE `ads_app_video_alarm_real` (\n"
                + "--   `scene_name` varchar(255) COMMENT'场景名称',\n"
                + "--   `camera_name` varchar(255) COMMENT'摄像头名称',\n"
                + "--   `content` varchar(255) COMMENT'报警内容',\n"
                + "--   `image` text COMMENT'图片ur',\n"
                + "--   `create_time` varchar(255) COMMENT'告警时间'\n"
                + "-- ) COMMENT '摄像头实时报警明细'\n"
                + "truncate table ads_app_video_alarm_real;\n"
                + "INSERT INTO  ads_app_video_alarm_real\n"
                + "SELECT\n"
                + "a.scene_name,\n"
                + "d.camera_name,\n"
                + "a.content,\n"
                + "a.image,\n"
                + "a.create_time,\n"
                + "b.streamid\n"
                + " FROM suanpan_jksp a\n"
                + " left join ods_gg_sxtinfo_f_d b on a.camera_ip=b.streamid\n"
                + " left join  ods_gg_sxtgl_sxtinfo_f_d c on b.gonggong_id=c.sxtinfo_id \n"
                + " left join ods_gg_sxtgl_f_d d ON c.sxtgl_id=d.gonggong_id\n"
                + " where d.camera_name is not null \n"
                + " AND  b.gonggong_is_deleted=0 and d.gonggong_is_deleted=0\n"
                + " order by a.create_time desc;";

        String sql5 =
            "INSERT INTO ads_app_video_alarm_real\n"
                + "SELECT a.scene_name, d.camera_name, a.content, a.image, a.create_time\n"
                + "\t, b.streamid\n"
                + "FROM suanpan_jksp a\n"
                + "\tLEFT JOIN ods_gg_sxtinfo_f_d b ON a.camera_ip = b.streamid\n"
                + "\tLEFT JOIN ods_gg_sxtgl_sxtinfo_f_d c ON b.gonggong_id = c.sxtinfo_id\n"
                + "\tLEFT JOIN ods_gg_sxtgl_f_d d ON c.sxtgl_id = d.gonggong_id\n"
                + "WHERE d.camera_name IS NOT NULL\n"
                + "\tAND b.gonggong_is_deleted = 0\n"
                + "\tAND d.gonggong_is_deleted = 0\n"
                + "ORDER BY a.create_time DESC";
        boolean isSelectSQl = SqlParserUtil.checkIsSelectSQl(sql5, EDbVendor.dbvmysql);

        System.out.println(isSelectSQl);
        //    List<FieldInfo> fieldInfoBySQLScrip = getFieldInfoBySQLScrip(sql);
        //    String sql = "insert into b select * from a ";
        //    //    String createTable = SqlParserUtil.getCreateTableAndView(sql);
        //    //    System.out.println(createTable);
        //    StringBuilder sb = new StringBuilder();
        //    List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
        //    for (SQLStatement sqlStatement : sqlStatements) {
        //      SchemaStatVisitor schemaStatVisitor = SQLUtils.createSchemaStatVisitor(DbType.mysql);
        //      String s = sqlStatement.toString();
        //      sqlStatement.accept(schemaStatVisitor);
        //      Map<TableStat.Name, TableStat> tables = schemaStatVisitor.getTables();
        //      if (Objects.isNull(tables)) {
        //        continue;
        //      }
        //      tables.forEach(
        //          (table, tableOperator) -> {
        //            if (tableOperator.getCreateCount() > 0) {
        //              sb.append(table);
        //            }
        //          });
        //    }
        //
        //    System.out.println(sb.toString());

        String sql21 = "select id from table where name = ?";
    }
}
